﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Terminal.Advanced_AEUC_settings_controls.Advanced_controls;
using Terminal.Advanced_AEUC_settings_controls.Scripting;
using System.IO;
using System.Threading;
using System.Reflection;
using Auxiliaries;
using CmdSrv;
using OMXTreeViewNodes;

namespace OMXParamsConfig
{
    /// <summary>
    /// Main view of the OMX Configuration application
    /// </summary>
    public partial class OMXParamForm : Form, IOMXTreeViewParentForm
    {
        delegate void UIInvokeDelegate(object something);

        const string CTX_MENU_ADD_ROOT = "Create new component";
        const string CTX_MENU_LOAD_ROOT = "Load component from file";
        const string CTX_MENU_PROG_PROP = "Program properties";
        const string CTX_MENU_SCRIPTING = "Start scripting";
        const string CTX_MENU_FAST_SCRIPTS = "Fast scripts menu";
        const string CTX_MENU_COMM_LOG_ON = "Communication log: On";
        const string CTX_MENU_COMM_LOG_OFF = "Communication log: Off";
        const string CTX_MENU_DATA_SERVICE = "Spawn data reception service";
        const string CTX_MENU_ABOUT = "About";

        const string CTX_MENU_PWR_RESET = "Reset";
        const string CTX_MENU_PWR_ON = "On";
        const string CTX_MENU_PWR_OFF = "Off";

        bool script_server_mode = false;
        CmdSrv.CmdSrv cmdServer = null;
        ScriptingModule scrFastScriptDiag = null;

        /// <summary>
        /// Public contrsutcor
        /// </summary>
        public OMXParamForm(bool script_srv)
        {
            InitializeComponent();

            CreateCommLinkChannel(true);

            script_server_mode = script_srv;

            tvOMXParamStructTree.ContextMenuStrip = new ContextMenuStrip();
            EventHandler eh = new EventHandler(ContextMenuHandler);
            tvOMXParamStructTree.ContextMenuStrip.Items.Add(CTX_MENU_ADD_ROOT, null, eh);
            tvOMXParamStructTree.ContextMenuStrip.Items.Add(CTX_MENU_LOAD_ROOT, null, eh);
            tvOMXParamStructTree.ContextMenuStrip.Items.Add(new ToolStripSeparator());
            tvOMXParamStructTree.ContextMenuStrip.Items.Add(CTX_MENU_SCRIPTING, null, eh);
            tvOMXParamStructTree.ContextMenuStrip.Items.Add(CTX_MENU_FAST_SCRIPTS, null, eh);
            tvOMXParamStructTree.ContextMenuStrip.Items.Add(CTX_MENU_COMM_LOG_ON, null, eh);
            tvOMXParamStructTree.ContextMenuStrip.Items.Add(CTX_MENU_COMM_LOG_OFF, null, eh);
            tvOMXParamStructTree.ContextMenuStrip.Items.Add(CTX_MENU_DATA_SERVICE, null, eh);
            tvOMXParamStructTree.ContextMenuStrip.Items.Add(new ToolStripSeparator());
            tvOMXParamStructTree.ContextMenuStrip.Items.Add(CTX_MENU_PROG_PROP, null, eh);

            MainMenuStrip.Items.Add("Components");
            ((ToolStripMenuItem)MainMenuStrip.Items[0]).DropDownItems.Add(CTX_MENU_ADD_ROOT, null, eh);
            ((ToolStripMenuItem)MainMenuStrip.Items[0]).DropDownItems.Add(CTX_MENU_LOAD_ROOT, null, eh);

            MainMenuStrip.Items.Add(CTX_MENU_FAST_SCRIPTS, null, eh);

            MainMenuStrip.Items.Add("Tools");
            ((ToolStripMenuItem)MainMenuStrip.Items[2]).DropDownItems.Add(CTX_MENU_SCRIPTING, null, eh);
            ((ToolStripMenuItem)MainMenuStrip.Items[2]).DropDownItems.Add(CTX_MENU_COMM_LOG_ON, null, eh);
            ((ToolStripMenuItem)MainMenuStrip.Items[2]).DropDownItems.Add(CTX_MENU_COMM_LOG_OFF, null, eh);
            ((ToolStripMenuItem)MainMenuStrip.Items[2]).DropDownItems.Add(CTX_MENU_DATA_SERVICE, null, eh);
            MainMenuStrip.Items.Add("Settings");
            ((ToolStripMenuItem)MainMenuStrip.Items[3]).DropDownItems.Add(CTX_MENU_PROG_PROP, null, eh);
            ((ToolStripMenuItem)MainMenuStrip.Items[3]).DropDownItems.Add(CTX_MENU_ABOUT, null, eh);

            MainMenuStrip.Items.Add("Com power switch");
            ((ToolStripMenuItem)MainMenuStrip.Items[4]).DropDownItems.Add(CTX_MENU_PWR_RESET, null, eh);
            ((ToolStripMenuItem)MainMenuStrip.Items[4]).DropDownItems.Add(CTX_MENU_PWR_ON, null, eh);
            ((ToolStripMenuItem)MainMenuStrip.Items[4]).DropDownItems.Add(CTX_MENU_PWR_OFF, null, eh);
        }

        private void OMXParamForm_Load(object sender, EventArgs e)
        {
            try
            {
                FileInfo finf = new FileInfo(Properties.Settings.Default.LastLoadedComponent);
                if (finf.Exists)
                {
                    Thread UILoadUp = new Thread(new ParameterizedThreadStart(deserializeOMXParamTreeViewFile));
                    UILoadUp.IsBackground = true;
                    UILoadUp.Start((object)finf);
                }
            }
            catch
            {
            }
        }

        #region Connection and connection status reporting
        /// <summary>
        /// Communication module reference.
        /// </summary>
        CommLink.CommLink commLink;
        /// <summary>
        /// Creates a communication link object based on user media selection.
        /// </summary>
        public void CreateCommLinkChannel(bool defaultConnection)
        {
            if (commLink != null)
            {
                commLink.CommClose();
                commLink = null;
            }

            object enumSelection = null;
            if (defaultConnection)
                enumSelection = CommLink.CommLink.GetDefaultConnectionType();

            if (enumSelection == null)
                enumSelection = CreateSelectDialogBoxFromEnum(typeof(CommLink.CommLink.CommLinkType), CommLink.Properties.Settings.Default.Default_communication_type);

            if (enumSelection == null)
            {
                MessageBox.Show("Communication channel not established!");
                enumSelection = CommLink.CommLink.CommLinkType.No_Communication;
            }

            commLink = new CommLink.CommLink((CommLink.CommLink.CommLinkType)enumSelection);
            commLink.OnConnectionStatusEvent += new CommLink.CommLink.ConnectionStatusEvent(commLink_OnConnStateChange);
            commLink.establishConnection();
        }

        private void tsslConnectionStatus_Click(object sender, EventArgs e)
        {
            CreateCommLinkChannel(false);
        }
        /// <summary>
        /// Gets the communcation channel name
        /// </summary>
        /// <returns>Communication channel name</returns>
        public string GetCommLinkChannelName()
        {
            if (commLink != null)
                return commLink.connectionTypeName();
            else
                return "";
        }
        /// <summary>
        /// Returns a reference to the active communication object
        /// </summary>
        /// <returns>Communication link object reference</returns>
        public CommLink.CommLink GetCommLinkObject()
        {
            return commLink;
        }
        /// <summary>
        /// Creates a dialog box for selecting an item from an enum.
        /// </summary>
        /// <param name="tEnum">Enum type object that will be displayed in the combo box</param>
        /// <param name="defSelection">Default enum selection if any</param>
        /// <returns>The selected enum field</returns>
        public object CreateSelectDialogBoxFromEnum(Type tEnum, string defSelection)
        {
            Form frm = new Form();
            Graphics gfx = frm.CreateGraphics();
            SizeF tmpStringMeasure;
            frm.Text = "Communication media select";
            frm.Size = new Size(450, 300);

            frm.Controls.Add(new Label());
            frm.Controls.Add(new ComboBox());
            frm.Controls.Add(new Button());
            frm.Controls.Add(new Button());

            frm.Controls[0].Text = "Communication type";
            frm.Controls[0].Location = new Point(5, 5);
            tmpStringMeasure = gfx.MeasureString(frm.Controls[0].Text, frm.Controls[0].Font);
            frm.Controls[0].Size = new Size((int)tmpStringMeasure.Width, frm.Controls[0].Size.Height);

            frm.Controls[1].Location = new Point(frm.Controls[0].Location.X + frm.Controls[0].Size.Width + 5, frm.Controls[0].Location.Y);
            tmpStringMeasure = new SizeF(0, 0);
            if (defSelection == null)
            {
                defSelection = "";
            }
            foreach (FieldInfo fInfo in tEnum.GetFields(BindingFlags.Public | BindingFlags.Static))
            {
                if (tmpStringMeasure.Width < gfx.MeasureString(fInfo.Name, frm.Controls[1].Font).Width)
                    tmpStringMeasure = gfx.MeasureString(fInfo.Name, frm.Controls[1].Font);
                ((ComboBox)frm.Controls[1]).Items.Add(fInfo.Name);
                if (fInfo.Name == defSelection)
                    ((ComboBox)frm.Controls[1]).SelectedItem = ((ComboBox)frm.Controls[1]).Items[((ComboBox)frm.Controls[1]).Items.Count - 1];
            }

            frm.Controls[1].Size = new Size((int)tmpStringMeasure.Width + 10, frm.Controls[1].Size.Height);

            frm.Controls[2].Text = "Ok";
            frm.Controls[2].Location = new Point(frm.Controls[0].Location.X, frm.Controls[1].Location.Y + frm.Controls[1].Size.Height + 5);
            frm.AcceptButton = (Button)frm.Controls[2];
            frm.AcceptButton.DialogResult = DialogResult.OK;
            tmpStringMeasure = gfx.MeasureString(frm.Controls[2].Text, frm.Controls[2].Font);
            frm.Controls[2].Size = new Size((int)tmpStringMeasure.Width + 50, frm.Controls[2].Size.Height);

            frm.Controls[3].Text = "Cancel";
            frm.Controls[3].Location = new Point(frm.Controls[2].Location.X + frm.Controls[2].Size.Width + 5, frm.Controls[2].Location.Y);
            frm.CancelButton = (Button)frm.Controls[3];
            tmpStringMeasure = gfx.MeasureString(frm.Controls[3].Text, frm.Controls[3].Font);
            frm.Controls[3].Size = new Size((int)tmpStringMeasure.Width + 50, frm.Controls[3].Size.Height);

            if (frm.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    return Enum.Parse(tEnum, ((ComboBox)frm.Controls[1]).SelectedItem.ToString());
                }
                catch
                {
                    return null;
                }

            }

            return null;
        }
        #endregion

        //This handle should be called when updating/deserializing of the ucTabPage underlying controls have finished.
        void ucTabPage_OnUCInternControlsUpdated()
        {
            if (UIDeserializationLock)
            {
                TreeViewUnlock();
            }

            if (script_server_mode)
            {
                /*
                 * TODO: Start the named pipe server here and minimize the app to the system tray.
                 * Named pipe server should take a delegate function of type void (string), which 
                 * woul dbe the scrDiag.executeScriptFile (could be replaced later on with other
                 * function to support more complex commands).
                 */
                
                to_tray();

                scrFastScriptDiag = new ScriptingModule(new ScriptingModule.GetAvailableOMXComponentsDelegate(getAvailableOMXComp),
                                                    new ScriptingModule.GetActiveCommLinkDelegate(GetCommLinkObject), true,
                                                    new ScriptingModule.CreateDefaultComLinkDelegate(CreateCommLinkChannel), null);

                scrFastScriptDiag.Show();
                scrFastScriptDiag.WindowState = FormWindowState.Minimized;
                scrFastScriptDiag.Hide();
                cmdServer = new CmdSrv.CmdSrv(CmdSrv.CmdSrv.CMD_SRV_TYPE.WIN_NAMED_PIPES, new CmdSrv.CmdSrv.cmd_exec_func_delegate(scrFastScriptDiag.executeScriptFileOld));
            }
        }

        void TreeViewUnlock()
        {
            UIDeserializationLock = false;
            tvOMXParamStructTree.Enabled = true;
        }

        void TreeViewLock()
        {
            UIDeserializationLock = true;
            tvOMXParamStructTree.Enabled = false;
        }

        delegate void showBaloonTipDelegate(string text, Point coorXY, int delay);

        void updateUI_showBaloonTip(string text, Point coorXY, int duration)
        {
            //As this may not runing on the UI, invoke the UI thread to set the new values.
            if (InvokeRequired)
            {
                BeginInvoke(new showBaloonTipDelegate(updateUI_showBaloonTip), new object[] { text, coorXY, duration });
            }
            else
            {
                ToolTip ttParseInf = new ToolTip();
                ttParseInf.IsBalloon = true;
                ttParseInf.ShowAlways = true;
                ttParseInf.Show(text, this, coorXY, duration);
            }
        }

        delegate void getCompNameAndPost_crossUI(int compId, out string name, out Point Pos, out UCTabPage comUCTab);

        void getCompNameAndPost(int compId, out string name, out Point Pos, out UCTabPage comUCTab)
        {
            Pos = new Point();
            name = "";
            comUCTab = null;

            Pos = /*PointToScreen(*/Location/*)*/;
            if (compId != -1)
            {
                for (int i = 0; i < tvOMXParamStructTree.Nodes.Count; i++)
                {
                    if (((OMXParamTreeViewRootNode)tvOMXParamStructTree.Nodes[i]).CompInstanceID == compId)
                    {
                        comUCTab = ((OMXParamTreeViewRootNode)tvOMXParamStructTree.Nodes[i]).UCTabPage;
                        name = ((OMXParamTreeViewRootNode)tvOMXParamStructTree.Nodes[i]).OMXCopmName;
                        /*
                        if (tvOMXParamStructTree.Nodes[i].Bounds.Location.Y > -1 && tvOMXParamStructTree.Nodes[i].Bounds.Location.Y < tvOMXParamStructTree.Size.Height)
                            Pos = tvOMXParamStructTree.Nodes[i].Bounds.Location;
                        else if (tvOMXParamStructTree.Nodes[i].Bounds.Location.Y < tvOMXParamStructTree.Size.Height)
                            Pos = new Point(tvOMXParamStructTree.Nodes[i].Bounds.Location.X, 0);
                        else
                            Pos = new Point(tvOMXParamStructTree.Nodes[i].Bounds.Location.X, tvOMXParamStructTree.Size.Height);
                        break;
                        */
                    }
                }
            }
        }

        void ucTabPage_OnparamsStreamParse(UCTabPage.ParameterStreamParseResult state, int compId, int tabId)
        {
            Point disLoc;
            string msg;
            int timeOut = 5000;
            UCTabPage comUCTab;
            string tabName = "Unknown";

            getCompNameAndPost(compId, out msg, out disLoc, out comUCTab);

            if (msg != "" && comUCTab != null)
            {
                tabName = comUCTab.tabPageTitle(tabId);

                switch (state)
                {
                    case UCTabPage.ParameterStreamParseResult.PARSE_OK:
                        msg = "Field update at " + msg + "::" + tabName;
                        commLink.errorMessage(msg);
                        break;
                    case UCTabPage.ParameterStreamParseResult.PARSE_FAIL:
                        msg = "Error while parsing";
                        commLink.errorMessage(msg);
                        break;
                    case UCTabPage.ParameterStreamParseResult.PARSE_UNRECOGNIZED:
                        msg = "Unrecognized error(s) at " + msg + "::" + tabName;
                        commLink.errorMessage(msg);
                        break;
                    case UCTabPage.ParameterStreamParseResult.CONFIG_APPLY_ACK:
                        msg = "Config applied acknowledge received for " + msg + "::" + tabName;
                        commLink.errorMessage(msg);
                        break;
                    case UCTabPage.ParameterStreamParseResult.OMX_COMP_HANDLE:
                        msg = msg + " handle received";
                        break;
                    case UCTabPage.ParameterStreamParseResult.OMX_COMP_CMD:
                        msg = "Component " + msg + " command acknowledge received.";
                        break;
                    case UCTabPage.ParameterStreamParseResult.OMX_COMP_PORT_BUFF_ALLOC:
                        msg = "Component " + msg + " port buffers allocated.";
                        break;
                }

                //updateUI_showBaloonTip(msg, disLoc, timeOut);
            }
        }

        void commLink_OnConnStateChange(CommLink.CommLinkAbstract.ConnectionStates eState)
        {
            switch (eState)
            {
                case CommLink.CommLinkAbstract.ConnectionStates.Connected:
                    tsslConnectionStatus.Text = "Connected";
                    toolStripConnectionStatusLabel.Visible = true;
                    toolStripConnectionStatusLabel.Text = "via " + GetCommLinkChannelName() + ".";
                    for (int i = 0; i < tvOMXParamStructTree.Nodes.Count; i++)
                    {
                        ((OMXParamTreeViewRootNode)tvOMXParamStructTree.Nodes[i]).UCTabPage.AttachCommLinkChannel(commLink);
                    }
                    break;
                case CommLink.CommLinkAbstract.ConnectionStates.NotConnected:
                    tsslConnectionStatus.Text = "Not connected";
                    toolStripConnectionStatusLabel.Visible = false;
                    if (commLink != null)
                        commLink.hideCommLog();
                    break;
                case CommLink.CommLinkAbstract.ConnectionStates.ServerError:
                    tsslConnectionStatus.Text = "Server error";
                    toolStripConnectionStatusLabel.Visible = false;
                    if (commLink != null)
                        commLink.hideCommLog();
                    break;
            }
        }

        /// <summary>
        /// Creates an OMX Component and structure array from available components
        /// </summary>
        /// <returns>Array of available OMX Components to be used by scripting module</returns>
        public ScriptingModule.OMXComponent[] getAvailableOMXComp()
        {
            ScriptingModule.OMXComponent[] compTbl = new ScriptingModule.OMXComponent[tvOMXParamStructTree.Nodes.Count];
            for (int i = 0; i < tvOMXParamStructTree.Nodes.Count; i++)
            {
                OMXParamTreeViewNodeSelected(tvOMXParamStructTree.Nodes[i]);
                compTbl[i] = new ScriptingModule.OMXComponent();
                compTbl[i].omxName = ((OMXParamTreeViewRootNode)tvOMXParamStructTree.Nodes[i]).Text;
                compTbl[i].messages = ((OMXParamTreeViewRootNode)tvOMXParamStructTree.Nodes[i]).UCTabPage.getCMsgDefs();
                compTbl[i].gtpProperties = ((OMXParamTreeViewRootNode)tvOMXParamStructTree.Nodes[i]).UCTabPage.getTabPageProps();
            }

            return compTbl;
        }
        /// <summary>
        /// Returns the string name representation for OMX component with specified id
        /// </summary>
        /// <param name="id">Id of the OMX component</param>
        /// <returns>Name of the OMX component</returns>
        public string GetCompName(uint id)
        {
            for (int i = 0; i < tvOMXParamStructTree.Nodes.Count; i++)
            {
                if (((OMXParamTreeViewRootNode)tvOMXParamStructTree.Nodes[i]).CompInstanceID == id)
                    return ((OMXParamTreeViewRootNode)tvOMXParamStructTree.Nodes[i]).Text;
            }

            return "UNKNOWN";
        }
        /// <summary>
        /// Posts an information message to the active comm link console
        /// </summary>
        /// <param name="msg">String message to post</param>
        public void PostInfoMessage(string msg)
        {
            commLink.errorMessage(msg);
        }

        #region OMX Struct tree load from file function

        #region File deserialization
        #region Section nodes laoding
        private TreeNode loadOMXParamTreeView(BinaryReader fsr, UCTabPage refUC)
        {
            int sectVersion;
            try
            {
                sectVersion = fsr.ReadInt32();
                if (sectVersion < OMXParamTreeViewSectionNode.OMXCompSectNodeVerMin || sectVersion > OMXParamTreeViewSectionNode.OMXCompSectNodeVerMax)
                    throw new Exception("Invalid version number - assuming pre-version 0 node.");
            }
            catch(Exception ex)
            {
                fsr.BaseStream.Position -= 4;
                sectVersion = 0;
                commLink.errorMessage(ex.Message);
            }

            switch (sectVersion)
            {
                case 0:
                    return loadOMXParamTreeView_Ver_x0(fsr, refUC);
                default:
                    throw new Exception("Unsupported node version encountered.");
            }
        }

        #region Section node version loading
        TreeNode loadOMXParamTreeView_Ver_x0(BinaryReader fsr, UCTabPage refUC)
        {
            string name = fsr.ReadString();
            Int32 filesCount = fsr.ReadInt32();
            string[] filePaths = new string[filesCount];
            int[] refPages = new int[filesCount];
            for (int i = 0; i < filesCount; i++)
            {
                filePaths[i] = fsr.ReadString();
                refPages[i] = fsr.ReadInt32();
            }
            TreeNode tNode = new OMXParamTreeViewSectionNode(name, filePaths, refPages, refUC, this);
            Int32 childCount = fsr.ReadInt32();
            while (childCount-- > 0)
            {
                tNode.Nodes.Add(loadOMXParamTreeView(fsr, refUC));
            }

            return tNode;
        }
        #endregion
        #endregion

        #region Non-UI read thread
        private void deserializeOMXParamTreeViewFile(object file)
        {
            FileInfo finf = (FileInfo)file;
            OMXParamTreeViewRootNode tNodeBase = null;
            BinaryReader fsr = new BinaryReader(finf.OpenRead());
            try
            {
                int rootVersion;
                try
                {
                    rootVersion = fsr.ReadInt32();
                    if (rootVersion < OMXParamTreeViewRootNode.OMXCompRootNodeVerMin || rootVersion > OMXParamTreeViewRootNode.OMXCompRootNodeVerMax)
                        throw new Exception("Invalid version number - assuming pre-version 0 node.");
                }
                catch (Exception ex)
                {
                    fsr.BaseStream.Position -= 4;
                    rootVersion = 0;
                    commLink.errorMessage(ex.Message);
                }

                switch (rootVersion)
                {
                    case 0:
                        tNodeBase = loadOMXParamRootTreeView_Ver_x0(fsr, finf.Directory.ToString());
                        break;
                    case 1:
                        tNodeBase = loadOMXParamRootTreeView_Ver_x1(fsr, finf.Directory.ToString());
                        break;
                    case 2:
                        tNodeBase = loadOMXParamRootTreeView_Ver_x2(fsr, finf.Directory.ToString());
                        break;
                    case 3:
                        tNodeBase = loadOMXParamRootTreeView_Ver_x3(fsr, finf.Directory.ToString());
                        break;
                }
                tNodeBase.infParamTreeViewFile = finf;
                tNodeBase.UCTabPage.AttachCommLinkChannel(commLink);
                tNodeBase.UCTabPage.OnParamsStreamParse += new UCTabPage.paramsStreamParse(ucTabPage_OnparamsStreamParse);
                tNodeBase.UCTabPage.OnUCInternControlsUpdated += new UCTabPage.UCInternControlsUpdated(ucTabPage_OnUCInternControlsUpdated);

                int sectCount = fsr.ReadInt32();
                for (int i = 0; i < sectCount; i++)
                {
                    tNodeBase.Nodes.Add(loadOMXParamTreeView(fsr, tNodeBase.UCTabPage));
                }
            }
            catch (Exception ex)
            {
                tNodeBase = null;
                commLink.errorMessage(ex.Message);
            }
            finally
            {
                Properties.Settings.Default.LastLoadedComponent = finf.FullName;
                Properties.Settings.Default.Save();
                fsr.Close();
                finf.Refresh();
            }

            if (InvokeRequired)
            {
                BeginInvoke(new UIInvokeDelegate(SetRootTreeNode), new object[] { tNodeBase });
            }
            else
            {
                SetRootTreeNode(tNodeBase);
            }
        }
        #endregion
        private void SetRootTreeNode(object somsing)
        {
            OMXParamTreeViewRootNode tNodeBase = (OMXParamTreeViewRootNode)somsing;
            if (tNodeBase != null)
            {
                tvOMXParamStructTree.Nodes.Add(tNodeBase);
                //Apply invalid component id to all subsequent pages on load up
                //tNodeBase.CompInstanceID = unchecked((uint)-1);
                tNodeBase.CompInstanceID = unchecked((uint)0);
            }
            OMXParamTreeViewNodeSelected(tNodeBase);
        }
        #endregion

        bool UIDeserializationLock = false;

        private void loadOMXParamTreeViewFile()
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.AddExtension = true;
            ofd.DefaultExt = "omxtv";
            ofd.Filter = "*.omxtv|*.omxtv";
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                FileInfo finf = new FileInfo(ofd.FileName);
                if (finf.Exists)
                {
                    Thread UILoadUp = new Thread(new ParameterizedThreadStart(deserializeOMXParamTreeViewFile));
                    UILoadUp.IsBackground = true;
                    UILoadUp.Start((object)finf);
                }
            }
        }

        #region root node version loading
        OMXParamTreeViewRootNode loadOMXParamRootTreeView_Ver_x0(BinaryReader fsr, string dirPath)
        {
            return new OMXParamTreeViewRootNode(fsr.ReadString(), /*ucTabPage,*/ this, dirPath + "\\" + fsr.ReadString());
        }
        OMXParamTreeViewRootNode loadOMXParamRootTreeView_Ver_x1(BinaryReader fsr, string dirPath)
        {
            string name = fsr.ReadString();
            string OMXname = fsr.ReadString();
            OMXParamTreeViewRootNode tNodeBase = new OMXParamTreeViewRootNode(name, /*ucTabPage,*/ this, dirPath + "\\" + fsr.ReadString());
            tNodeBase.OMXCopmName = OMXname;
            return tNodeBase;
        }
        OMXParamTreeViewRootNode loadOMXParamRootTreeView_Ver_x2(BinaryReader fsr, string dirPath)
        {
            string name = fsr.ReadString();
            string OMXname = fsr.ReadString();
            string cfgDCC = fsr.ReadString();
            OMXParamTreeViewRootNode tNodeBase = new OMXParamTreeViewRootNode(name, /*ucTabPage,*/ this, dirPath + "\\" + fsr.ReadString());
            tNodeBase.OMXCopmName = OMXname;
            tNodeBase.cfgDCC = cfgDCC;
            return tNodeBase;
        }
        OMXParamTreeViewRootNode loadOMXParamRootTreeView_Ver_x3(BinaryReader fsr, string dirPath)
        {
            string name = fsr.ReadString();
            string OMXname = fsr.ReadString();
            string cfgDCC = fsr.ReadString();
            string uriDCC = fsr.ReadString();
            string bufDCC = fsr.ReadString();
            OMXParamTreeViewRootNode tNodeBase = new OMXParamTreeViewRootNode(name, /*ucTabPage,*/ this, dirPath + "\\" + fsr.ReadString());
            tNodeBase.OMXCopmName = OMXname;
            tNodeBase.cfgDCC = cfgDCC;
            tNodeBase.uriDCC = uriDCC;
            tNodeBase.bufDCC = bufDCC;
            return tNodeBase;
        }
        #endregion
        #endregion

        #region OMX Struct tree save to file function

        public void saveOMXParamTreeView(OMXParamTreeViewSectionNode sect, BinaryWriter fBin)
        {
            fBin.Write(sect.OMXCompSectNodeVer);
            fBin.Write(sect.OMXParamSectionName);
            Int32 fileChilds = 0;
            string[] filePaths = new string[sect.Nodes.Count];
            Int32[] refPages = new int[sect.Nodes.Count];
            Int32 SubLvlChilds = 0;
            for (int i = 0; i < sect.Nodes.Count; i++)
            {
                if (sect.Nodes[i].GetType() == typeof(OMXParamTreeViewSectionNode))
                {
                    SubLvlChilds++;
                }
                else if (sect.Nodes[i].GetType() == typeof(OMXParamTreeViewTabPageRefNode))
                {
                    filePaths[fileChilds] = ((OMXParamTreeViewTabPageRefNode)sect.Nodes[i]).OMXParamTabPageName;
                    refPages[fileChilds++] = ((OMXParamTreeViewTabPageRefNode)sect.Nodes[i]).OMXParamTabPageRefIndx;
                }
            }

            fBin.Write(fileChilds);
            for (int i = 0; i < fileChilds; i++)
            {
                fBin.Write(filePaths[i]);
                fBin.Write(refPages[i]);
            }
            fBin.Write(SubLvlChilds);
            for (int i = 0, k = 0; i < sect.Nodes.Count && k < SubLvlChilds; i++)
            {
                if (sect.Nodes[i].GetType() == typeof(OMXParamTreeViewSectionNode))
                {
                    k++;
                    saveOMXParamTreeView((OMXParamTreeViewSectionNode)sect.Nodes[i], fBin);
                }
            }

        }

        public void saveOMXParamTreeView(OMXParamTreeViewRootNode root, FileInfo fInf)
        {
            BinaryWriter fBin = null;

            if (fInf == null)
            {
                SaveFileDialog sfd = new SaveFileDialog();
                sfd.AddExtension = true;
                sfd.DefaultExt = "omxtv";
                sfd.Filter = "*.omxtv|*.omxtv";
                if (sfd.ShowDialog() == DialogResult.OK)
                {
                    fInf = new FileInfo(sfd.FileName);
                }
                else
                {
                    return;
                }
            }
            try
            {
                fBin = new BinaryWriter(fInf.Create());

                fBin.Write(root.OMXCompRootNodeVer);
                fBin.Write(root.Text);
                fBin.Write(root.OMXCopmName);
                fBin.Write(root.cfgDCC);
                fBin.Write(root.uriDCC);
                fBin.Write(root.bufDCC);
                fBin.Write(root.infUCTabPageControlsFile.Name);
                fBin.Write((Int32)root.Nodes.Count);

                for (int i = 0; i < root.Nodes.Count; i++)
                {
                    saveOMXParamTreeView((OMXParamTreeViewSectionNode)(root.Nodes[i]), fBin);
                }

                root.UCTabPage.SaveUserSettingDefinitionsFile(root.infUCTabPageControlsFile);
                root.infParamTreeViewFile = fInf;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                commLink.errorMessage(ex.Message);
            }
            finally
            {
                if (fBin != null)
                    fBin.Close();
            }

        }

        #endregion

        #region Tree View event handlers and menus

        /// <summary>
        /// Holds reference to the currently selected tree root node
        /// </summary>
        OMXParamTreeViewRootNode curSelectedRoot;

        private void tvOMXParamStructTree_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                OMXParamTreeViewNodeSelected(e.Node);
            }          
        }

        private void OMXParamForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (commLink != null)
            {
                commLink.CommClose();
                commLink = null;
            }
        }
 
        public void OMXParamTreeViewNodeSelected(TreeNode Node)
        {
            if (Node != null)
            {

                #region Check if the root has changed and if so save old one and reload UI

                TreeNode newSelectedRoot = Node;
                while (newSelectedRoot.Parent != null)
                    newSelectedRoot = newSelectedRoot.Parent;

                if (curSelectedRoot != newSelectedRoot)
                {
                    TreeViewLock();

                    Text = ((OMXParamTreeViewRootNode)newSelectedRoot).uctabDefFilePath();

                    pnlUCTabPlaceHolder.Controls.Clear();
                    ((OMXParamTreeViewRootNode)newSelectedRoot).loadUCTabPage(pnlUCTabPlaceHolder);

                    TreeViewUnlock();
                }

                curSelectedRoot = (OMXParamTreeViewRootNode)newSelectedRoot;

                #endregion

                if (Node.GetType() == typeof(OMXParamTreeViewSectionNode))
                {
                    ((OMXParamTreeViewSectionNode)Node).SelectFirstOMXParamTabPageNode();
                }
                else if (Node.GetType() == typeof(OMXParamTreeViewTabPageRefNode))
                {
                    ((OMXParamTreeViewTabPageRefNode)Node).SelectOMXParamTabPage();
                }
            }
            else
            {
                pnlUCTabPlaceHolder.Controls.Clear();
                curSelectedRoot = null;
            }
        }

        private void ContextMenuHandler(object sender, EventArgs ea)
        {
            ToolStripItem tmpItem = (ToolStripItem)sender;
            ea.GetType();

            if (tmpItem.Text == CTX_MENU_ADD_ROOT)
            {
                AuxQueryBox secCrtForm = new AuxQueryBox(AuxQueryBox.IfModeSel.Section_create);
                if (secCrtForm.ShowDialog() == DialogResult.OK)
                {
                    SaveFileDialog sfd = new SaveFileDialog();
                    sfd.AddExtension = true;
                    sfd.DefaultExt = "omxtv";
                    sfd.Filter = "*.omxtv|*.omxtv";
                    if (sfd.ShowDialog() == DialogResult.OK)
                    {
                        OMXParamTreeViewRootNode tmpNode = new OMXParamTreeViewRootNode(secCrtForm.GetInputText(), /*ucTabPage,*/ this, sfd.FileName.Replace(".omxtv", ".tsd"));
                        tmpNode.infParamTreeViewFile = new FileInfo(sfd.FileName);
                        tmpNode.UCTabPage.AttachCommLinkChannel(commLink);
                        tmpNode.UCTabPage.OnParamsStreamParse += new UCTabPage.paramsStreamParse(ucTabPage_OnparamsStreamParse);
                        tmpNode.UCTabPage.OnUCInternControlsUpdated += new UCTabPage.UCInternControlsUpdated(ucTabPage_OnUCInternControlsUpdated);
                        
                        tvOMXParamStructTree.Nodes.Add(tmpNode);
                        OMXParamTreeViewNodeSelected(tmpNode);

                        saveOMXParamTreeView(tmpNode, tmpNode.infParamTreeViewFile);
                    }
                }
            }
            else if (tmpItem.Text == CTX_MENU_LOAD_ROOT)
            {
                loadOMXParamTreeViewFile();
            }
            else if (tmpItem.Text == CTX_MENU_PROG_PROP)
            {
                ProgProp ppForm = new ProgProp();
                ppForm.ShowDialog();
            }
            else if (tmpItem.Text == CTX_MENU_SCRIPTING || tmpItem.Text == CTX_MENU_FAST_SCRIPTS)
            {
                if (tmpItem.Text == CTX_MENU_FAST_SCRIPTS)
                {
                    fastScriptMenu();
                }
                else
                {
                    ScriptingModule scrDiag = new ScriptingModule(new ScriptingModule.GetAvailableOMXComponentsDelegate(getAvailableOMXComp),
                                                                    new ScriptingModule.GetActiveCommLinkDelegate(GetCommLinkObject), false,
                                                                    new ScriptingModule.CreateDefaultComLinkDelegate(CreateCommLinkChannel), this);
                    scrDiag.Show();
                }
            }
            else if (tmpItem.Text == CTX_MENU_COMM_LOG_ON)
            {
                //tmpItem.Text = CTX_MENU_COMM_LOG_OFF;
                if (commLink != null)
                {
                    commLink.displayCommLog();
                }
            }
            else if (tmpItem.Text == CTX_MENU_COMM_LOG_OFF)
            {
                //tmpItem.Text = CTX_MENU_COMM_LOG_ON;
                if (commLink != null)
                {
                    commLink.hideCommLog();
                }
            }
            else if (tmpItem.Text == CTX_MENU_DATA_SERVICE)
            {
                if(tvOMXParamStructTree.Nodes.Count > 0)
                {
                    uint datTransf = ((OMXParamTreeViewRootNode)tvOMXParamStructTree.Nodes[0]).UCTabPage.GetBoundDataMessageID();
                    uint[] datCtrlStat = ((OMXParamTreeViewRootNode)tvOMXParamStructTree.Nodes[0]).UCTabPage.GetBoundDataMessageControlStat();
                    uint[] datType = ((OMXParamTreeViewRootNode)tvOMXParamStructTree.Nodes[0]).UCTabPage.GetBoundDataMessageDataTypes();

                    DataHandlerService.DataHandlerService drhc = new DataHandlerService.DataHandlerService(commLink, GetCompName, PostInfoMessage);

                    drhc.SetDataCommIds(datTransf, datCtrlStat[0], datCtrlStat[1], datCtrlStat[2], datCtrlStat[3], datCtrlStat[4], datType[0], datType[1]);
                    drhc.Show();
                }
            }
            else if (tmpItem.Text == CTX_MENU_PWR_OFF)
            {
                if (!ComPowerSwitch.ComSwitch.PowerOff())
                    MessageBox.Show("Error accessing COM power switch");
            }
            else if (tmpItem.Text == CTX_MENU_PWR_ON)
            {
                if (!ComPowerSwitch.ComSwitch.PowerOn())
                    MessageBox.Show("Error accessing COM power switch");
            }
            else if (tmpItem.Text == CTX_MENU_PWR_RESET)
            {
                if (!ComPowerSwitch.ComSwitch.Reset())
                    MessageBox.Show("Error accessing COM power switch");
            }
            else if (tmpItem.Text == CTX_MENU_ABOUT)
            {
                List<Type> tp = new List<Type>();
                tp.Add(typeof(OMXParamsConfig.OMXParamForm));
                tp.Add(typeof(UCTabPage));
                tp.Add(typeof(ScriptingModule));
                tp.Add(typeof(CommLink.CommLinkAbstract));
                tp.Add(typeof(Auxiliaries.HEX_converter));
                tp.Add(typeof(ComPowerSwitch.ComSwitch));
                tp.Add(typeof(DataHandlerService.DataHandlerService));
                tp.Add(typeof(ProgressBars.ProgBarsDisp));
                tp.Add(typeof(AssInfo.About));

                AssInfo.About abt = new AssInfo.About(tp.ToArray());
                abt.ShowDialog();
            }
        }
        #endregion

        void fastScriptMenu()
        {
            if (scrFastScriptDiag == null)
            {
                scrFastScriptDiag = new ScriptingModule(new ScriptingModule.GetAvailableOMXComponentsDelegate(getAvailableOMXComp),
                                                                new ScriptingModule.GetActiveCommLinkDelegate(GetCommLinkObject), true,
                                                                new ScriptingModule.CreateDefaultComLinkDelegate(CreateCommLinkChannel), this);
                scrFastScriptDiag.FormClosed += new FormClosedEventHandler(scrFastScriptDiag_FormClosed);
                scrFastScriptDiag.Show();
            }
            else
            {
                scrFastScriptDiag.WindowState = FormWindowState.Normal;
                scrFastScriptDiag.Focus();
            }
        }

        void scrFastScriptDiag_FormClosed(object sender, FormClosedEventArgs e)
        {
            scrFastScriptDiag = null;
        }

        #region Tray minimization options
        private void to_tray()
        {
            Hide();
            WindowState = FormWindowState.Minimized;
        }

        private void to_display()
        {
            Show();
            WindowState = FormWindowState.Normal;
            Focus();
        }

        private void show_state()
        {
            if (WindowState == FormWindowState.Minimized)
                Hide();
            else
                Show();
        }

        private void MainForm_Resize(object sender, EventArgs e)
        {
            show_state();
        }

        private void closeToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void hideToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (cmsTaskBarIcn.Items[0].Text == "Hide")
            {
                to_tray();
            }
            else
            {
                to_display();
            }
        }

        private void cmsTaskBarIcn_Opening(object sender, CancelEventArgs e)
        {
            if ((WindowState == FormWindowState.Normal || WindowState == FormWindowState.Maximized) && script_server_mode)
            {
                cmsTaskBarIcn.Items[0].Text = "Hide";
            }
            else
                cmsTaskBarIcn.Items[0].Text = "Show";
        }

        private void faToolStripMenuItem_Click(object sender, EventArgs e)
        {
            fastScriptMenu();
        }
        #endregion
    }
}
